﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpArch.Core.DomainModel;
using NHibernate.Validator.Constraints;

namespace Peak.Core
{
  public class Story : EntityWithBusinessRules
  {
    [NotNullNotEmpty]
    public virtual string Name { get; set; }
    public virtual string Category { get; set; }    
    public virtual string Description { get; set; }    
    public virtual string HowToDemo { get; set; }
    public virtual int Priority { get; set; }
    public virtual int OpenedTaskCount { get; set; }    
    public virtual string Requester { get; set; }

    public virtual DateTime? StartDate { get; set; }
    public virtual DateTime? EndDate { get; set; }

    private StoryStatus _status;
    public virtual StoryStatus Status
    {
      get
      {
        return _status;
      }
      set
      {
        if (!RulesEnabled())
        {
          _status = value;
          return;
        }


        if(_status != value)
        {
          if (_status == StoryStatus.ToDo)
          {
            StartDate = DateTime.Now;
          }

          if (value == StoryStatus.Done)
          {
            if (CurrentSprintStory.Sprint != null && CurrentSprintStory.Sprint.EndDate < DateTime.Now)
            {
              EndDate = CurrentSprintStory.Sprint.EndDate;
            }
            else
            {
              EndDate = DateTime.Now;
            }
          }

          if (value != StoryStatus.ToDo && CurrentSprintStory.Sprint != null && CurrentSprintStory.Sprint.Status == SprintStatus.Planning)
          {
            throw new SprintPlaningException();
          }
          if (value == StoryStatus.Done && !CurrentSprintStory.AllFinished())
          {
            throw new NotFinishedTasksOrBugsException();
          }
          if (value != StoryStatus.ToDo && CurrentSprintStory.Sprint != null && CurrentSprintStory.Sprint.Status == SprintStatus.Finished)
          {
            throw new SprintFinishedException();
          }
          if (value == StoryStatus.Done && CurrentSprintStory.Sprint != null)
          {
            CurrentSprintStory.Sprint.RealVelocity += StoryPoints;
          }
          if (_status == StoryStatus.Done && CurrentSprintStory.Sprint != null)
          {
            CurrentSprintStory.Sprint.RealVelocity -= StoryPoints;
          }
          _status = value;
        }
      }
    }
    
    public virtual Project Project{ get; set;}        
    public virtual IList<StoryChange> Changes { get; set; }
    private double _storyPoints;
    public virtual double StoryPoints
    {
      get
      {
        return _storyPoints;
      }
      set
      {
        if (_storyPoints != value)
        {
          if (RulesEnabled() && Project != null)
          {
            Project.StoryPoints += value - _storyPoints;
          }
          
          _storyPoints = value;
        }
      }
    }
    
    public virtual DateTime Created { get; set; }
    [NotNullNotEmpty]
    public virtual string CreatedBy { get; set; }

    public virtual DateTime Modified { get; set; }
    [NotEmpty]
    public virtual string ModifiedBy { get; set; }    

    public virtual IList<SprintStory> SprintStories { get; set; }
    
    public Story()
    {
      Status = StoryStatus.ToDo;      
      SprintStories = new List<SprintStory>();
      if(SprintStories != null) // when StoryProxy class is generated by nhibernate
      {
        SprintStories.Add(new SprintStory(){ Story = this });
      }
      Changes = new List<StoryChange>();
    }

    public virtual SprintStory CurrentSprintStory
    {
      get
      {
        return SprintStories[SprintStories.Count - 1];
      }
    }

    public virtual void AddSprintStory(SprintStory sprintStory)
    {
      SprintStories.Add(sprintStory);
      sprintStory.Story = this;
      sprintStory.StoryPoints = StoryPoints;      
    }

    public virtual void RemoveSprintStory(SprintStory sprintStory)
    {
      SprintStories.Remove(sprintStory);
      sprintStory.Story = null;
    }
  }
}